package com.shinbada.modules.sys.web;

import com.auth0.jwt.JWT;
import com.shinbada.common.json.AjaxJson;
import com.shinbada.config.properties.ShinProperites;
import com.shinbada.core.security.shiro.JWTUtil;
import com.shinbada.core.security.shiro.annotation.OpenApi;
import com.shinbada.core.web.BaseController;
import com.shinbada.core.web.GlobalErrorController;
import com.shinbada.modules.sys.entity.SysConfig;
import com.shinbada.modules.sys.entity.User;
import com.shinbada.modules.sys.service.UserService;
import com.shinbada.modules.sys.utils.UserUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录Controller
 *
 * @author initcap
 * @version 2016-5-31
 */
@Slf4j
@RestController
@Api(tags = "登录管理")
public class LoginController extends BaseController {

    @Autowired
    private UserService userService;

    @OpenApi
    @PostMapping("/sys/login")
    @ApiOperation("【开放接口】登录接口")
    public AjaxJson login(@RequestParam("userName") String userName,
                          @RequestParam("password") String password) {
        User user = UserUtils.getByLoginName(userName);
        if (user == null) {
            return AjaxJson.error("用户不存在!");
        } else if (ShinProperites.NO.equals(user.getLoginFlag())) {
            return AjaxJson.error("该用户已经被禁止登陆!");
        } else {
            UserUtils.clearCache(user);
            user = UserUtils.getByLoginName(userName);
            log.info("【用户登录】根据用户名获取用户登录信息,登录密码为 : {}", user.getPassword());
            if (UserService.validatePassword(password, user.getPassword())) {
                return AjaxJson.success()
                        .put(JWTUtil.TOKEN, JWTUtil.createAccessToken(userName, user.getPassword()))
                        .put(JWTUtil.REFRESH_TOKEN, JWTUtil.createRefreshToken(userName, user.getPassword()));
            } else {
                SysConfig config = UserUtils.getConfig();
                if (config.getErrInputPasswordTimes() == null || config.getErrInputPasswordTimes().equals(-1)) {
                    return AjaxJson.error("用户名或者密码错误!");
                } else {
                    checkAndAddErrInputPasswordTimes(user, config.getErrInputPasswordTimes());
                    return AjaxJson.error("用户名或者密码连续错误[" + user.getErrInputPassword() + "]次,错误超过" + config.getErrInputPasswordTimes() + "次账号将被锁定!");
                }
            }
        }
    }

    private void checkAndAddErrInputPasswordTimes(User user, Integer errInputPasswordTimes) {
        user.setErrInputPassword(user.getErrInputPassword() == null ? 1 : user.getErrInputPassword() + 1);
        boolean disable = errInputPasswordTimes != null &&
                errInputPasswordTimes != -1 &&
                user.getErrInputPassword() >= errInputPasswordTimes;
        if (disable) {
            // 锁定账号，不能登录
            userService.disableLogin(user.getId(), ShinProperites.NO);
        }
        userService.addErrInputPassword(user.getId());
    }

    @GetMapping("/sys/refreshToken")
    @ApiOperation("刷新token")
    public AjaxJson accessTokenRefresh(String refreshToken, HttpServletRequest request, HttpServletResponse response) {
        if (JWTUtil.verify(refreshToken) == 1) {
            GlobalErrorController.response4022(request, response);

        } else if (JWTUtil.verify(refreshToken) == 2) {
            return AjaxJson.error("用户名密码错误");
        }

        String loginName = JWTUtil.getLoginName(refreshToken);
        String password = UserUtils.getByLoginName(loginName).getPassword();
        //创建新的accessToken
        String accessToken = JWTUtil.createAccessToken(loginName, password);

        //下面判断是否刷新 REFRESH_TOKEN，如果refreshToken 快过期了 需要重新生成一个替换掉 , REFRESH_TOKEN 有效时长是应该为accessToken有效时长的2倍
        long minTimeOfRefreshToken = 2 * ShinProperites.newInstance().getExpireTime();
        //refreshToken创建的起始时间点
        Long refreshTokenExpirationTime = JWT.decode(refreshToken).getExpiresAt().getTime();
        //(refreshToken过期时间- 当前时间点) 表示refreshToken还剩余的有效时长，如果小于2倍accessToken时长 ，则刷新 REFRESH_TOKEN
        if (refreshTokenExpirationTime - System.currentTimeMillis() <= minTimeOfRefreshToken) {
            //刷新refreshToken
            refreshToken = JWTUtil.createRefreshToken(loginName, password);
        }

        return AjaxJson.success()
                .put(JWTUtil.TOKEN, accessToken)
                .put(JWTUtil.REFRESH_TOKEN, refreshToken);
    }

    @OpenApi
    @ApiOperation("【开放接口】用户退出")
    @GetMapping("/sys/logout")
    public AjaxJson logout() {
        UserUtils.logout();
        return AjaxJson.success("退出成功");
    }

}
